package com.hts.utils;

import cn.hutool.core.convert.Convert;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.Options;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;


/**
 * Aviator表达式引擎基本使用
 * 核心内部设定 对外开发计算方式
 * <dependency>
 * 			<groupId>com.googlecode.aviator</groupId>
 * 			<artifactId>aviator</artifactId>
 * 			<version>5.3.3</version>
 *</dependency>
 */
public class AviatorUtils {


    public static void main(String[] args) {
//        使用示例
        String expression = "a+b*(c-b)";
        Map<String,Object> env = new HashMap<>();
        env.put("a",1);
        env.put("b",2);
        env.put("c",3);
        BigDecimal bigDecimal = bigDecimalExecute(expression, env);
        System.out.println(bigDecimal);
    }

    /**
     * 转换成bigDecimal计算
     * @param expression 文本表达式
     * @param env 绑定变量环境
     * @return
     */
    public static BigDecimal bigDecimalExecute(String expression,Map<String,Object> env){
        for (Map.Entry<String, Object> stringObjectEntry : env.entrySet()) {
            Object value = stringObjectEntry.getValue();
            stringObjectEntry.setValue(new BigDecimal(String.valueOf(value)));
        }
        return  (BigDecimal) createExpression(expression).execute(env);

    }

    /**
     * 执行表达式引擎
     * @param expression 文本表达式
     * @param env
     * @param returnType
     * @return
     * @param <T>
     */
    public static <T> T execute(String expression,Map<String,Object> env,Class<T> returnType){
        Object execute = createExpression(expression).execute(env);
        return Convert.convert(returnType,execute);
    }

    /**
     * 创建 Aviator表达式引擎
     * @param expression 文本表达式
     * @return
     */
    private static Expression createExpression(String expression){
        //获取默认计算器实例
        AviatorEvaluatorInstance aviatorEvaluatorInstance = AviatorEvaluator.getInstance();
        //防止注入
        Set<Class<?>> whitelist = new HashSet<>();
        whitelist.add(String.class);
        whitelist.add(Integer.class);
        whitelist.add(Double.class);
        whitelist.add(Float.class);
        whitelist.add(Boolean.class);
        whitelist.add(Math.class);
        whitelist.add(BigDecimal.class);
        whitelist.add(ArrayList.class);
        whitelist.add(Map.class);

        aviatorEvaluatorInstance.setOption(Options.ALLOWED_CLASS_SET,whitelist);
        //开始表达式
        return aviatorEvaluatorInstance.compile(expression,true);

    }
}
